/*
 * @(#) RedisJobRecorder
 * 版权声明 厦门畅享信息技术有限公司, 版权所有 违者必究
 *
 * <br> Copyright:  Copyright (c) 2024
 * <br> Company:厦门畅享信息技术有限公司
 * <br> @author Administrator
 * <br> 2024-01-05 17:40:56
 */

package com.lost.octopus.es.processor.scheduler;

import com.lost.octopus.es.processor.constant.Constant;

import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

import javax.annotation.Resource;

import lombok.extern.log4j.Log4j2;

/**
 * redis 索引重建锁
 * @author linzz
 * @date 2024/1/5 17:40
 */
@Component
@Log4j2
public class RedisIndexRebuildRecorder {
    @Resource
    private RedissonClient redissonClient;

    /**
     * lock(), 拿不到lock就不罢休，不然线程就一直block
     */
    public RLock lock(String lockKey) {
        RLock lock = redissonClient.getLock(lockKey);
        lock.lock();
        return lock;
    }

    /**
     * leaseTime为加锁时间，单位为秒
     */
    public RLock lock(String lockKey, long leaseTime) {
        RLock lock = redissonClient.getLock(lockKey);
        lock.lock(leaseTime, TimeUnit.SECONDS);
        return null;
    }

    /**
     * timeout为加锁时间，时间单位由unit确定
     */
    public RLock lock(String lockKey, TimeUnit unit, long timeout) {
        RLock lock = redissonClient.getLock(lockKey);
        lock.lock(timeout, unit);
        return lock;
    }

    /**
     * @param lockKey   锁 key
     * @param unit      单位
     * @param waitTime  等待时间
     * @param leaseTime 锁有效时间
     * @return 加锁成功? true:成功 false: 失败
     */
    public boolean tryLock(String lockKey, TimeUnit unit, long waitTime, long leaseTime) {

        RLock lock = redissonClient.getLock(lockKey);
        try {
            return lock.tryLock(waitTime, leaseTime, unit);
        } catch (InterruptedException e) {
            return false;
        }
    }

    /**
     * unlock
     */
    public void unlock(String lockKey) {
        RLock lock = redissonClient.getLock(lockKey);
        //if (lock.isLocked() && lock.isHeldByCurrentThread()) {
        if (lock.isLocked()) {
            lock.unlock();
        }
    }

    /**
     * unlock
     * @param lock 锁
     */
    public void unlock(RLock lock) {
        lock.unlock();
    }



    /**
     * 锁定正在重建的index
     * @param indexClassName 业务标识
     */
    public void indexRebuildLock(Class indexClassName) {
        // 检查是否存在待继续任务
        String key = redisKey(indexClassName.getSimpleName());
        lock(key, TimeUnit.SECONDS, 30L);
    }


    /**
     * 索引是否被锁定
     * @param indexClassName 业务标识
     * @return 索引是否被锁定
     */
    public boolean indexHasLocked(Class indexClassName) {
        // 检查是否存在待继续任务
        String key = redisKey(indexClassName.getSimpleName());

        RLock lock = redissonClient.getLock(key);

        if (lock.isLocked()) {
            log.info("索引被锁定，可能在做别名（{}）切换处理, 开始尝试获取锁...", indexClassName.getSimpleName());
            try {
                // 取得锁后返回 true, 即没有其他锁定，5毫秒后锁就自动过期
                return !lock.tryLock(35000, 5, TimeUnit.MILLISECONDS);
            } catch (Exception e) {
                log.error("加锁失败或者35s不能取得锁， error = ", e);
                return true;
            }
        }
        return false;

    }

    /**
     * 获取正在同步的任务，任务名称等于索引名称
     * @param indexClassName 业务标识
     */
    public void unLockIndex(Class indexClassName) {
        String key = redisKey(indexClassName.getSimpleName());
        unlock(key);
    }

    /**
     * 获取redisKey
     * @param indexClassName 业务key
     * @return 累加前缀
     */
    protected String redisKey(String indexClassName) {
        return Constant.FULL_SYNC_INDEX_LOCK_REDIS_KEY_PREFIX + indexClassName;
    }
}
